home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
mac
/
files
/
sat
/
msat09.tgz
/
XTLM.C
< prev
next >
Wrap
Text File
|
1994-09-17
|
20KB
|
945 lines
/*
* Copyright 1992, 1993, 1994 John Melton (G0ORX/N6LYT)
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
xtlm.c
telemery decoding program for PACSATs
- - -
This software was written to provide a receive only capability
for collecting files and directories from satellites running
the Pacsat Protocols running on the Linux Operating System.
This program has been run using the 1.0 version of the
Linux kernel with the patches from Alan Cox to provide AX.25
encapsulation of SLIP.
The TNC must be setup for KISS.
John Melton
G0ORX, N6LYT
4 Charlwoods Close
Copthorne
West Sussex
RH10 3QZ
England
INTERNET: g0orx@amsat.org
n6lyt@amsat.org
john@images.demon.co.uk
J.D.Melton@slh0613.icl.wins.co.uk
History:
-------
0.1 Initial version G4KLX
*/
#define VERSION_STRING "(version 0.1 by g4klx)"
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Viewport.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/ax25.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include "crc.h"
Display *dpy;
XtAppContext app_context;
typedef struct
{
XFontStruct *button_font, *text_font;
}
Resources;
Resources resources;
Widget toplevel, compwindow, quitbutton, lognextbutton, button[10], viewport,
pagelabel, timelabel, tlmlabel, crclabel, form, label[23];
XtResource resource_list[] =
{
{"buttonFont", XtCFont, XtRFontStruct, sizeof(XFontStruct *),
XtOffsetOf(Resources, button_font), XtRString, XtDefaultFont},
{"textFont", XtCFont, XtRFontStruct, sizeof(XFontStruct *),
XtOffsetOf(Resources, text_font), XtRString, XtDefaultFont}
};
Arg shell_args[] =
{
{XtNtitle, (XtArgVal)NULL}
};
Arg form_args[] =
{
{XtNdefaultDistance, (XtArgVal)0}
};
Arg button_args[] =
{
{XtNcallback, (XtArgVal)NULL},
{XtNlabel, (XtArgVal)NULL},
{XtNfromHoriz, (XtArgVal)NULL},
{XtNfont, (XtArgVal)NULL},
{XtNresize, (XtArgVal)False},
{XtNvertDistance, (XtArgVal)6},
{XtNhorizDistance, (XtArgVal)8},
{XtNtop, XtChainTop},
{XtNbottom, XtChainTop},
{XtNleft, XtChainLeft},
{XtNright, XtChainLeft}
};
Arg title_args[] =
{
{XtNfromVert, (XtArgVal)NULL},
{XtNfromHoriz, (XtArgVal)NULL},
{XtNfont, (XtArgVal)NULL},
{XtNwidth, (XtArgVal)70},
{XtNvertDistance, (XtArgVal)0},
{XtNhorizDistance, (XtArgVal)5},
{XtNlabel, (XtArgVal)""},
{XtNheight, (XtArgVal)25},
{XtNresize, False},
{XtNborderWidth, (XtArgVal)0},
{XtNjustify, XtJustifyLeft},
{XtNtop, XtChainTop},
{XtNbottom, XtChainTop},
{XtNleft, XtChainLeft},
{XtNright, XtChainRight}
};
Arg label_args[] =
{
{XtNfromVert, (XtArgVal)NULL},
{XtNfont, (XtArgVal)NULL},
{XtNvertDistance, (XtArgVal)6},
{XtNhorizDistance, (XtArgVal)8},
{XtNwidth, (XtArgVal)550},
{XtNlabel, (XtArgVal)""},
{XtNborderWidth, (XtArgVal)0},
{XtNheight, (XtArgVal)15},
{XtNresize, False},
{XtNjustify, XtJustifyLeft},
{XtNtop, XtChainTop},
{XtNbottom, XtChainTop},
{XtNleft, XtChainLeft},
{XtNright, XtChainLeft}
};
Arg viewport_args[] =
{
{XtNfromVert, (XtArgVal)NULL},
{XtNwidth, (XtArgVal)600},
{XtNheight, (XtArgVal)300},
{XtNallowVert, True},
{XtNforceBars, True},
{XtNresize, True},
{XtNvertDistance, (XtArgVal)0},
{XtNhorizDistance, (XtArgVal)0},
{XtNtop, XtChainTop},
{XtNbottom, XtChainBottom},
{XtNleft, XtChainLeft},
{XtNright, XtChainRight}
};
#define PID_TEXT 0xF0
#define MAXBUFFER 300
#define ONLINE_MODE 0
#define FILE_MODE 1
int mode = ONLINE_MODE;
char satelliteId[16];
int current_page = 0;
int tlmBytes = 0;
int crcErrors = 0;
time_t timestamp = 0;
int s_raw = 0;
FILE *fpraw = NULL;
struct equation
{
struct equation *next; /* A D S */
char type; /* A D S */
int channel; /* A D S */
char *title; /* A D S */
int value; /* A D S */
int page, row, column; /* A D S */
int occurence; /* A */
double a, b, c; /* A */
int status; /* D */
char *state0, *state1; /* S */
};
struct equation *first = NULL;
/*
* Convert a call from the shifted ascii form used in an
* AX.25 packet.
*/
int ConvertCall(char *c, char *call)
{
char *ep = c + 6;
int ct = 0;
while (ct < 6)
{
if (((*c >> 1) & 127) == ' ') break;
*call = (*c >> 1) & 127;
call++;
ct++;
c++;
}
if ((*ep & 0x1E) != 0)
{
*call = '-';
call++;
call += sprintf(call, "%d", (int)(((*ep) >> 1) & 0x0F));
}
*call = '\0';
if (*ep & 1) return 0;
return 1;
}
void UpdateStatus(void)
{
static int lastPage = -1;
static time_t lastTime = -1;
static int lastTLM = -1;
static int lastCRC = -1;
char label[40], *s;
Arg args[1];
if (lastPage != current_page)
{
sprintf(label, "Page %2d", current_page);
XtSetArg(args[0], XtNlabel, label);
XtSetValues(pagelabel, args, ONE);
lastPage = current_page;
}
if (lastTime != timestamp)
{
s = ctime(×tamp);
s[24] = '\0';
sprintf(label, "Timestamp %s", s);
XtSetArg(args[0], XtNlabel, label);
XtSetValues(timelabel, args, ONE);
lastTime = timestamp;
}
if (lastTLM != tlmBytes)
{
sprintf(label, "TLM bytes %5d", tlmBytes);
XtSetArg(args[0], XtNlabel, label);
XtSetValues(tlmlabel, args, ONE);
lastTLM = tlmBytes;
}
if (lastCRC != crcErrors)
{
sprintf(label, "CRC errors %3d", crcErrors);
XtSetArg(args[0], XtNlabel, label);
XtSetValues(crclabel, args, ONE);
lastCRC = crcErrors;
}
}
void DisplayBinary(char *s, int value)
{
int i;
*s = '\0';
for (i = 0; i < 12; i++)
{
if (value & (0x800 >> i))
strcat(s, "1");
else
strcat(s, "0");
}
}
void DrawTLMPage(int page)
{
struct equation *equation;
char *buffer[23], *title, data[15];
Arg args[1];
double result;
int i, row, column, offset, value;
current_page = page;
for (i = 0; i < 23; i++)
{
buffer[i] = XtMalloc(85);
memset(buffer[i], ' ', 84);
buffer[i][84] = '\0';
}
equation = first;
while (equation != NULL)
{
if (equation->page == page)
{
title = equation->title;
column = equation->column;
row = equation->row;
value = equation->value;
switch (equation->type)
{
case 'A':
offset = column * 27;
strncpy(buffer[row] + offset, title, strlen(title));
if (value != -1)
{
result = equation->a * (double)value * (double)value +
equation->b * (double)value +
equation->c;
sprintf(data, "%.2f", result);
strncpy(buffer[row] + offset + 25 - strlen(data), data, strlen(data));
}
break;
case 'D':
offset = column * 27;
strncpy(buffer[row] + offset, title, strlen(title));
if (value != -1)
{
DisplayBinary(data, value);
strncpy(buffer[row] + offset + 25 - strlen(data), data, strlen(data));
}
break;
case 'S':
offset = column * 42;
strncpy(buffer[row] + offset, title, strlen(title));
if (value != -1)
{
if (value)
strncpy(buffer[row] + offset + 30, equation->state1, strlen(equation->state1));
else
strncpy(buffer[row] + offset + 30, equation->state0, strlen(equation->state0));
}
break;
default:
break;
}
}
equation = equation->next;
}
for (i = 0; i < 23; i++)
{
XtSetArg(args[0], XtNlabel, buffer[i]);
XtSetValues(label[i], args, ONE);
XtFree(buffer[i]);
}
}
void FillStates(int status, int value)
{
struct equation *equation;
int i, channel, bit;
for (i = 0; i < 12; i++)
{
channel = status + i;
bit = value & (0x800 >> i);
equation = first;
while (equation != NULL)
{
if (equation->channel == channel &&
equation->type == 'S')
equation->value = (bit != 0);
equation = equation->next;
}
}
}
void FillTLM(int value, int channel, int occurence)
{
struct equation *equation;
equation = first;
while (equation != NULL)
{
if (equation->channel == channel &&
equation->occurence == occurence &&
(equation->type == 'A' ||
equation->type == 'D'))
{
switch (equation->type)
{
case 'A':
equation->value = value;
break;
case 'D':
equation->value = value;
FillStates(equation->status, equation->value);
break;
default:
break;
}
return;
}
equation = equation->next;
}
}
void DecodeTLM(unsigned char *buffer, int bufsize)
{
int i;
int type, value;
int channel = 0;
int occurence = 0;
tlmBytes += bufsize;
if (!CheckCRC(buffer, bufsize))
{
crcErrors++;
UpdateStatus();
return;
}
timestamp = buffer[0] + (buffer[1] << 8) + (buffer[2] << 16) + (buffer[3] << 24);
buffer += 4;
bufsize -= 4;
UpdateStatus();
for (i = 0; i < (bufsize - 2); i += 2)
{
type = (buffer[i + 1] & 0xF0) >> 4;
value = buffer[i] + ((buffer[i + 1] & 0x0F) << 8);
switch (type)
{
case 2:
channel = value;
occurence = 0;
break;
case 1:
FillTLM(value, channel, occurence);
occurence++;
break;
case 0:
FillTLM(value, channel, occurence);
occurence = 0;
channel++;
break;
default:
break;
}
}
}
/*
* decode a received frame.
*/
void ProcessFrame(unsigned char *buffer, int bufsize)
{
int n;
int via;
unsigned char protocol;
char toCall[10];
char fromCall[10];
char viaCall[10];
/* check that frame is a kiss data frame */
/* ignore control frames - should not happen */
n = 0;
if ((buffer[n] & 0x0F) == 0)
{
n++;
/* decode the to/from address */
/* dont expect via address, but saves last if any */
via = ConvertCall(buffer + n, toCall);
n += 7;
via = ConvertCall(buffer + n, fromCall);
n += 7;
while (via)
{
via = ConvertCall(buffer + n, viaCall);
n += 7;
}
/* check for a UI frame */
if ((buffer[n] & 0xEF) == 0003)
{
n++;
protocol = buffer[n++];
/* see if the frame is a broadcast frame */
if (protocol == PID_TEXT && strcmp(toCall, "TLM") == 0)
{
DecodeTLM(buffer + n, bufsize - n);
DrawTLMPage(current_page);
if (fpraw != NULL)
{
fputc((bufsize - n) % 256, fpraw);
fputc((bufsize - n) / 256, fpraw);
fwrite(buffer + n, 1, bufsize - n, fpraw);
}
}
}
}
}
/*
* callback function when a frame is received.
*/
void GetFrame(XtPointer closure, int *s, XtInputId *Id)
{
unsigned char buffer[MAXBUFFER];
int bufsize;
if ((bufsize = recv(s_raw, buffer, MAXBUFFER, 0)) == -1)
{
perror("recv");
return;
}
ProcessFrame(buffer, bufsize);
}
/*
* the user wants to exit this program
*/
void QuitCb(Widget w, XtPointer client_data, XtPointer call_data)
{
if (fpraw != NULL) fclose(fpraw);
if (s_raw != 0) close(s_raw);
XtDestroyApplicationContext(app_context);
exit(0);
}
void LogNextCb(Widget w, XtPointer client_data, XtPointer call_data)
{
unsigned char buffer[300];
int bufsize;
Arg args[1];
time_t t;
if (mode == ONLINE_MODE)
{
if (fpraw == NULL)
{
time(&t);
sprintf(buffer, "%x.tlm", (int)t);
if ((fpraw = fopen(buffer, "w")) == NULL)
return;
XtSetArg(args[0], XtNlabel, "TLM Log On");
}
else
{
fclose(fpraw);
fpraw = NULL;
XtSetArg(args[0], XtNlabel, "TLM Log Off");
}
XtSetValues(lognextbutton, args, ONE);
}
else
{
if (!feof(fpraw))
{
bufsize = fgetc(fpraw);
bufsize += fgetc(fpraw) * 256;
fread(buffer, 1, bufsize, fpraw);
DecodeTLM(buffer, bufsize);
DrawTLMPage(current_page);
}
}
}
void PageCb(Widget w, XtPointer client_data, XtPointer call_data)
{
int page = (int)client_data;
if (page != current_page)
{
DrawTLMPage(page);
UpdateStatus();
}
}
void InsertChannel(struct equation *equation)
{
struct equation *current;
current = (struct equation *)XtMalloc(sizeof(struct equation));
*current = *equation;
if (first == NULL)
{
first = current;
}
else
{
equation = first;
while (equation->next != NULL)
equation = equation->next;
equation->next = current;
}
}
int ReadConfig(void)
{
char buffer[100];
char title[40], buf1[15], buf2[15];
FILE *fp;
struct equation current;
int page = 0, row = 0, column = 0;
int status = 0;
int count, i;
if ((fp = fopen("tlm.cfg", "r")) == NULL)
{
fprintf(stderr, "Cannot open tlm.cfg\n");
return(-1);
}
while (fgets(buffer, 100, fp) != NULL)
{
switch (*buffer)
{
case 'A':
sscanf(buffer, "%*c %d , %[^,], %lf , %lf , %lf , %d ,",
¤t.channel, title, ¤t.a,
¤t.b, ¤t.c, &count);
for (i = 0; i < count; i++)
{
current.next = NULL;
current.type = *buffer;
current.title = XtNewString(title);
current.occurence = i;
current.page = page;
current.row = row;
current.column = column;
current.value = -1;
InsertChannel(¤t);
column++;
if (column > 2)
{
column = 0;
row++;
}
if (row > 22)
{
column = 0;
row = 0;
page++;
}
}
break;
case 'D':
sscanf(buffer, "%*c %d , %[^,], ",
¤t.channel, title);
current.next = NULL;
current.type = *buffer;
current.status = status;
current.occurence = 0;
current.title = XtNewString(title);
current.page = page;
current.row = row;
current.column = column;
current.value = -1;
InsertChannel(¤t);
status += 12;
column++;
if (column > 2)
{
column = 0;
row++;
}
if (row > 22)
{
column = 0;
row = 0;
page++;
}
break;
case 'S':
if (current.type != 'S')
{
page++;
row = 0;
column = 0;
}
sscanf(buffer, "%*c %d , %49[^,], %14[^, ] , %14[^, \n]",
¤t.channel, title, buf1, buf2);
current.next = NULL;
current.type = *buffer;
current.occurence = 0;
current.title = XtNewString(title);
current.state0 = XtNewString(buf1);
current.state1 = XtNewString(buf2);
current.page = page;
current.row = row;
current.column = column;
current.value = -1;
InsertChannel(¤t);
column++;
if (column > 1)
{
column = 0;
row++;
}
if (row > 22)
{
column = 0;
row = 0;
page++;
}
break;
case '+':
column += atoi(buffer + 1);
while (column > 2)
{
column -= 3;
row++;
}
if (row > 22)
{
column = 0;
row = 0;
page++;
}
break;
default:
break;
}
}
fclose(fp);
return(page + 1);
}
int main(int argc, char **argv)
{
static XtCallbackRec callback[2];
int i, pages;
char *s, title[80], name[10];
if ((s = getenv("SATELLITE")) == NULL)
{
printf("SATELLITE environment variable not set.\n");
return(1);
}
strcpy(satelliteId, s);
if ((s = getenv("XTLM")) != NULL)
{
if ((fpraw = fopen(s, "r")) == NULL)
{
printf("Cannot open file %s\n", s);
return(1);
}
mode = FILE_MODE;
}
sprintf(title, "xtlm:%s %s", satelliteId, VERSION_STRING);
strcat(satelliteId, "-0");
if ((pages = ReadConfig()) == -1) return(1);
toplevel = XtAppInitialize(&app_context, "Xpb", NULL, 0, &argc, argv,
NULL, shell_args, XtNumber(shell_args));
XtVaSetValues(toplevel, XtNtitle, title, NULL);
dpy = XtDisplay(toplevel);
XtGetApplicationResources(toplevel, &resources,
resource_list, XtNumber(resource_list),
NULL, ZERO);
compwindow = XtCreateManagedWidget("appForm", formWidgetClass,
toplevel, form_args, XtNumber(form_args));
callback[0].callback = QuitCb;
callback[0].closure = toplevel;
button_args[0].value = (XtArgVal)callback;
button_args[1].value = (XtArgVal)"Quit";
button_args[3].value = (XtArgVal)resources.button_font;
quitbutton = XtCreateManagedWidget("quitButton", commandWidgetClass,
compwindow, button_args, XtNumber(button_args));
callback[0].callback = LogNextCb;
callback[0].closure = toplevel;
button_args[0].value = (XtArgVal)callback;
if (mode == ONLINE_MODE)
button_args[1].value = (XtArgVal)"TLM Log Off";
else
button_args[1].value = (XtArgVal)"Next";
button_args[2].value = (XtArgVal)quitbutton;
button_args[3].value = (XtArgVal)resources.button_font;
lognextbutton = XtCreateManagedWidget("lognextButton", commandWidgetClass,
compwindow, button_args, XtNumber(button_args));
for (i = 0; i < pages; i++)
{
sprintf(title, "Page %d", i);
sprintf(name, "page%dButton", i);
callback[0].callback = PageCb;
callback[0].closure = (XtPointer)i;
button_args[0].value = (XtArgVal)callback;
button_args[1].value = (XtArgVal)title;
if (i == 0)
button_args[2].value = (XtArgVal)lognextbutton;
else
button_args[2].value = (XtArgVal)button[i - 1];
button[i] = XtCreateManagedWidget(name, commandWidgetClass,
compwindow, button_args, XtNumber(button_args));
}
title_args[0].value = (XtArgVal)quitbutton;
title_args[2].value = (XtArgVal)resources.button_font;
pagelabel = XtCreateManagedWidget("pageLabel", labelWidgetClass,
compwindow, title_args, XtNumber(title_args));
title_args[1].value = (XtArgVal)pagelabel;
title_args[3].value = (XtArgVal)250;
timelabel = XtCreateManagedWidget("timeLabel", labelWidgetClass,
compwindow, title_args, XtNumber(title_args));
title_args[1].value = (XtArgVal)timelabel;
title_args[3].value = (XtArgVal)130;
tlmlabel = XtCreateManagedWidget("tlmLabel", labelWidgetClass,
compwindow, title_args, XtNumber(title_args));
title_args[1].value = (XtArgVal)tlmlabel;
crclabel = XtCreateManagedWidget("crcLabel", labelWidgetClass,
compwindow, title_args, XtNumber(title_args));
viewport_args[0].value = (XtArgVal)pagelabel;
viewport = XtCreateManagedWidget("tlmViewport", viewportWidgetClass,
compwindow, viewport_args, XtNumber(viewport_args));
form = XtCreateManagedWidget("tlmForm", formWidgetClass,
viewport, form_args, XtNumber(form_args));
for (i = 0; i < 23; i++)
{
sprintf(name, "line%dLabel", i);
if (i > 0)
label_args[0].value = (XtArgVal)label[i - 1];
else
label_args[0].value = (XtArgVal)NULL;
label_args[1].value = (XtArgVal)resources.text_font;
label_args[4].value = (XtArgVal)600;
label[i] = XtCreateManagedWidget(name, labelWidgetClass,
form, label_args, XtNumber(label_args));
}
DrawTLMPage(0);
UpdateStatus();
if (mode == ONLINE_MODE)
{
/* open up the raw socket to receive all packets */
if ((s_raw = socket(AF_INET, SOCK_PACKET, htons(2))) == -1)
{
perror("socket");
return(1);
}
/* we want to be notified whenever a frame is received on the raw socket */
XtAppAddInput(app_context, s_raw, (XtPointer)XtInputReadMask, GetFrame, NULL);
}
XtRealizeWidget(toplevel);
XtAppMainLoop(app_context);
return(0);
}